package services

import (
	"gitee.com/kun_liu/to-log/app/models"
	"gitee.com/kun_liu/to-log/pkg/database"
	"gorm.io/gorm"
)

// CategoryService 分类服务
type CategoryService struct {
	db *gorm.DB
}

// NewCategoryService 创建分类服务
func NewCategoryService() *CategoryService {
	return &CategoryService{
		db: database.GetDB(),
	}
}

// GetCategories 获取分类列表
func (s *CategoryService) GetCategories() ([]models.Category, error) {
	var categories []models.Category
	result := s.db.Where("type = ?", "category").Order("'order' ASC").Find(&categories)
	return categories, result.Error
}

// GetCategoryBySlug 根据别名获取分类
func (s *CategoryService) GetCategoryBySlug(slug string) (models.Category, error) {
	var category models.Category
	result := s.db.Where("slug = ? AND type = ?", slug, "category").First(&category)
	return category, result.Error
}

// GetCategoryByID 根据ID获取分类
func (s *CategoryService) GetCategoryByID(id uint) (models.Category, error) {
	var category models.Category
	result := s.db.First(&category, id)
	return category, result.Error
}

// CreateCategory 创建分类
func (s *CategoryService) CreateCategory(category *models.Category) error {
	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 创建分类
	if err := tx.Create(category).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit().Error
}

// UpdateCategory 更新分类
func (s *CategoryService) UpdateCategory(category *models.Category) error {
	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 更新分类
	if err := tx.Save(category).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit().Error
}

// DeleteCategory 删除分类
func (s *CategoryService) DeleteCategory(id uint) error {
	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 获取分类
	var category models.Category
	if err := tx.First(&category, id).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 检查是否有子分类
	var childCount int64
	if err := tx.Model(&models.Category{}).Where("parent = ?", id).Count(&childCount).Error; err != nil {
		tx.Rollback()
		return err
	}

	if childCount > 0 {
		tx.Rollback()
		return gorm.ErrForeignKeyViolated
	}

	// 检查是否有关联的文章
	var postCount int64
	if err := tx.Model(&models.Post{}).Joins("JOIN relationships ON relationships.cid = posts.cid").Where("relationships.mid = ?", id).Count(&postCount).Error; err != nil {
		tx.Rollback()
		return err
	}

	if postCount > 0 {
		tx.Rollback()
		return gorm.ErrForeignKeyViolated
	}

	// 删除分类
	if err := tx.Delete(&category).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	return tx.Commit().Error
}

// GetCategoryTree 获取分类树
func (s *CategoryService) GetCategoryTree() ([]models.Category, error) {
	var categories []models.Category
	result := s.db.Where("type = ? AND parent = 0", "category").Order("order ASC").Find(&categories)
	if result.Error != nil {
		return nil, result.Error
	}

	// 递归获取子分类
	for i := range categories {
		err := s.getChildCategories(&categories[i])
		if err != nil {
			return nil, err
		}

		// 获取分类下的文章数量
		var count int64
		s.db.Model(&models.Post{}).Joins("JOIN relationships ON relationships.cid = posts.cid").Where("relationships.mid = ? AND posts.type = ?", categories[i].ID, "post").Count(&count)
		categories[i].Count = int(count)
	}

	return categories, nil
}

// getChildCategories 递归获取子分类
func (s *CategoryService) getChildCategories(category *models.Category) error {
	var children []models.Category
	result := s.db.Where("type = ? AND parent = ?", "category", category.ID).Order("order ASC").Find(&children)
	if result.Error != nil {
		return result.Error
	}

	// 递归获取子分类的子分类
	for i := range children {
		// 获取分类下的文章数量
		var count int64
		s.db.Model(&models.Post{}).Joins("JOIN relationships ON relationships.cid = posts.cid").Where("relationships.mid = ? AND posts.type = ?", children[i].ID, "post").Count(&count)
		children[i].Count = int(count)

		err := s.getChildCategories(&children[i])
		if err != nil {
			return err
		}
	}

	category.Children = children
	return nil
}
